#region

using Microsoft.Extensions.Options;
using Vin.Extension.Cache;
using Vin.Extension.Framework.Sms.Model;
using Vin.Extension.Framework.Sms.Phone.Model;
using Vin.Extension.Framework.Sms.Phone.ServiceInterface;
using Vin.Extension.Framework.Sms.Service;
using Vin.Extension.NLog;
using Vin.Tool.AspNetCore.Singleton;
using Vin.Tool.Attributes;
using Vin.Tool.Core.AssertCategory;
using Vin.Tool.Core.BasicTypeCategory;
using Vin.Tool.Core.ExceptionCategory;
using Vin.Tool.Core.JsonCategory;
using Vin.Tool.Core.RandomCategory;
using Vin.Tool.Domain.ExceptionModel;

#endregion

namespace Vin.Extension.Framework.Sms.Phone.Service;

[Service(Key)]
public class VinPhoneSmsService : VinSmsService
{
    public const string Key = "vin-phone-sms";

    // [Inject] private readonly IOptionsMonitor<VinPhoneOption> _optionsMonitor = null!;
    //
    // private VinPhoneOption Option => _optionsMonitor.CurrentValue;

    public VinPhoneOption Option => VinApp.GetConfig<VinPhoneOption>();

    private string CacheKey(string key) => Option.CacheCodeKey + key;


    public override async Task<string> SendCodeAsync(string businessDesc, string receiver,
        VinSmsSendOption? option = null)
    {
        // await base.SendCodeAsync(businessDesc, receiver, option);
        //
        // var key = Guid.NewGuid().ToString("N");
        // var code = RandomTool.RandomLong(100000, 1000000);
        // // 获取验证码
        // CacheFactory.SetCache<string>(CacheKey(key), code.ToString(), TimeSpan.FromMinutes(SmsConfig.Code.Expire));
        // await SendPhone(key, businessDesc, new List<string>() { receiver }, SmsConfig.Code.Title,
        //     SmsConfig.Code.Content, new
        //     {
        //         Code = code,
        //         SmsConfig.Code.Expire
        //     }, option);
        // return key;
        return await SendCodeAsync(businessDesc, receiver, SmsConfig.Code.Title, SmsConfig.Code.Content, null, option);
    }

    public override async Task<string> SendCodeAsync(string businessDesc, string receiver, string title, string content,
        object data, VinSmsSendOption? option = null)
    {
        await base.SendCodeAsync(businessDesc, receiver, option);

        var key = Guid.NewGuid().ToString("N");
        var code = RandomTool.RandomLong(100000, 1000000);
        data = new
        {
            Code = code,
            SmsConfig.Code.Expire
        };
        // 发送验证码
        if (!await SendPhone(key, businessDesc, new List<string>() { receiver }, title, content, data, option))
        {
            throw new BusinessException("短信发送失败，请稍后再试");
        }

        // 获取验证码
        CacheFactory.SetCache<string>(CacheKey(key), code.ToString(), TimeSpan.FromMinutes(SmsConfig.Code.Expire));
        return key;
    }


    public override async Task SendAsync(string businessDesc, string receiver, string title, string content,
        object data, VinSmsSendOption? option = null)
    {
        throw new NotImplementedException();
    }

    public override async Task SendAsync(string businessDesc, List<string> receivers, string title, string content,
        object data, VinSmsSendOption? option = null)
    {
        throw new NotImplementedException();
    }

    public override async Task<bool> VerifyCodeAsync(string uuid, string code)
    {
        var cacheKey = CacheKey(uuid);
        var cacheCode = CacheFactory.GetCache<string>(cacheKey);
        if (cacheCode.IsNullOrWhiteSpace())
        {
            return false;
        }

        if (cacheCode!.Equals(code, StringComparison.OrdinalIgnoreCase))
        {
            CacheFactory.RemoveCache(cacheKey);
            return true;
        }

        return await Task.FromResult(false);
    }

    public override async Task<string> GetCodeAsync(string uuid)
    {
        var cacheKey = CacheKey(uuid);
        var cacheCode = await CacheFactory.GetCacheAsync<string>(cacheKey);
        if (cacheCode.IsNullOrWhiteSpace())
        {
            return string.Empty;
        }

        return cacheCode!;
    }

    // -------------- 私有方法 --------------
    private async Task<bool> SendPhone(string businessId, string businessDesc, List<string> receivers, string title,
        string template, object? templateData, VinSmsSendOption? option = null)
    {
        // 检查发送服务
        if (Option.ServiceKey.IsNullOrEmpty())
        {
            Logger.Warn(LoggerName,
                "VinPhoneSmsService.SendPhone: ServiceKey is null or empty, please check your configuration.");
            return true;
        }

        // 整理发送内容
        var content = template.Format(templateData);
        if (option is VinPhoneSendOption phoneSendOption)
        {
            content = content.Format(phoneSendOption.TemplateData);
        }

        var sender = Option.ServiceKey!;
        var sendService = VinApp.GetServiceByHttpContext<ISendSmsService>(sender);
        string resultMsg;
        bool isSuccess;
        if (sendService != null)
        {
            (isSuccess, resultMsg) = await sendService.SendAsync(businessId, businessDesc, receivers, title,
                template, templateData, content, option);
        }
        else
        {
            isSuccess = false;
            resultMsg = "未找到发送服务，请检查配置或服务是否注册。";
        }

        await SaveLogAsync(businessId, businessDesc, sender, sendService?.Channel ?? "",
            receivers.ToCamelCaseJson(),
            title, content, isSuccess, resultMsg,
            template, templateData, option, senderInfo: sendService?.SenderInfo);

        return isSuccess;
    }
}